package com.yeskery.nut.core;

import java.io.InputStream;
import java.util.Arrays;
import java.util.Map;

/**
 * 通用响应接口
 * @author sprout
 * 2019-03-13 16:35
 * @version 1.0
 */
public interface Response {

	/**
	 * 设置响应的响应码
	 * @param code 响应码
	 */
	void setCode(int code);

	/**
	 * 设置响应的响应码
	 * @param responseCode 响应码
	 */
	default void setCode(ResponseCode responseCode) {
		setCode(responseCode.getCode());
	}

	/**
	 * 设置响应的字符集
	 * @param charSet 字符集
	 */
	void setCharSet(String charSet);

	/**
	 * 向响应中添加一个响应头
	 * @param nameAndValue 响应头
	 *
	 * @see NameAndValue
	 */
	void addHeader(NameAndValue nameAndValue);

	/**
	 * 向响应中添加一个响应头
	 * @param key 响应头名称
	 * @param value 响应头值
	 */
	default void addHeader(String key, String value) {
		addHeader(new NameAndValue(key, value));
	}

	/**
	 * 向响应中添加多个响应头
	 * @param headers 响应头集合
	 */
	default void addHeaders(Map<String, String> headers) {
		headers.forEach(this::addHeader);
	}

	/**
	 * 向响应中添加一个 Cookie
	 * @param cookie 需要添加的 Cookie 对象
	 */
	void addCookie(Cookie cookie);

	/**
	 * 向响应中添加多个 Cookie
	 * @param cookies 需要添加的 Cookie 对象
	 */
	default void addCookies(Cookie[] cookies) {
		Arrays.stream(cookies).forEach(this::addCookie);
	}

	/**
	 * 将空响应写入到响应中
	 */
	void writeEmpty();

	/**
	 * 从输入流中读取数据写入到响应中
	 * @param inputStream 输入流
	 */
	void write(InputStream inputStream);

	/**
	 * 从输入流中读取数据，并指定媒体类型写入到响应中
	 * @param inputStream 输入流
	 * @param mediaType 媒体类型
	 */
	void write(InputStream inputStream, MediaType mediaType);

	/**
	 * 从输入流中读取数据，并指定媒体类型写入到响应中
	 * @param inputStream 输入流
	 * @param mediaType 媒体类型
	 */
	void write(InputStream inputStream, String mediaType);

	/**
	 * 将指定的字节数组写入到响应中
	 * @param bytes 指定的字节数组
	 */
	void write(byte[] bytes);

	/**
	 * 将指定的字节数组，并指定媒体类型写入到响应中
	 * @param bytes 字节数组
	 * @param mediaType 媒体类型
	 */
	void write(byte[] bytes, MediaType mediaType);

	/**
	 * 将指定的字节数组，并指定媒体类型写入到响应中
	 * @param bytes 字节数组
	 * @param mediaType 媒体类型
	 */
	void write(byte[] bytes, String mediaType);

	/**
	 * 将指定的字符串写入到响应中
	 * @param content 指定的字符串
	 */
	void write(String content);

	/**
	 * 将指定的字符串，并使用 {@link MediaType#TEXT_HTML} 媒体类型写入到响应中
	 * @param content 指定的字符串
	 */
	void writeHtml(String content);

	/**
	 * 将指定的字符串，并使用 {@link MediaType#TEXT_XML} 媒体类型写入到响应中
	 * @param content 指定的字符串
	 */
	void writeXml(String content);

	/**
	 * 将指定的字符串，并使用 {@link MediaType#APPLICATION_JSON} 媒体类型写入到响应中
	 * @param content 指定的字符串
	 */
	void writeJson(String content);

	/**
	 * 将指定的对象，并使用 {@link MediaType#APPLICATION_JSON} 媒体类型写入到响应中
	 * @param object 指定的对象
	 */
	void writeJsonFromObject(Object object);

	/**
	 * 将指定的字符串，并指定媒体类型写入到响应中
	 * @param content 指定的字符串
	 * @param mediaType 媒体类型
	 */
	void write(String content, MediaType mediaType);

	/**
	 * 向客户端响应一个 {@link ResponseCode#FOUND} 重定向响应
	 * @param url 需要重定向的url
	 */
	default void sendRedirect(String url) {
		setCode(ResponseCode.FOUND);
		addHeader(HttpHeader.LOCATION, url);
		addHeader(HttpHeader.CONTENT_LENGTH, String.valueOf(0));
		writeEmpty();
	}

	/**
	 * 是否已经响应
	 * @return 是否已经响应
	 */
	boolean isResponse();
}
